package com.shanxia.codec.cmd;

import com.shanxia.codec.ProtocolDataBase;
import com.shanxia.codec.enums.DecodeEnum;
import lombok.Data;

import java.math.BigDecimal;
import java.util.Arrays;

import static com.shanxia.codec.Decoder.*;

/**
 * 充电桩签到信息上报
 * 充电桩上报签到信息
 */
@Data
public class Cmd106 extends ProtocolDataBase {

    public static final int MIN_SIZE = 101;

    private int v1;
    private int v2;
    private String sn;                       //充电桩编码
    private int sign;                        //标志
    private String softwareVer;              //充电桩软件版本
    private int projectType;                 //充电桩项目类型
    private int startNum;                    //启动次数
    private int uploadMode;                  //数据上传模式: 1：应答模式 2：主动上报模式
    private int signInterval;                //签到间隔时间
    private int innerVariate;                //运行内部变量: 0:正常工作模式 1:IAP 模式
    private int pileNum;                     //充电枪个数
    private int heartbeatPeriod;             //心跳上报周期
    private int overtimeCount;               //心跳包检测超时次数
    private int chargingRecordCount;         //充电记录数量
    private String currentTime;              //当前充电桩系统时间
    private String v3;
    private String v4;
    private String v5;
    private int randomNumber;                //桩生成随机数
    private String protocolVer="0.0";        //桩后台通信协议版本
    private int whitelistVer=0;                //白名单版本号
    private int deviceType=0;                  //设备类型: 0 充电桩 1 集中器

    public Cmd106(){
        super.setCmd(106);
    }

    public static Cmd106 decodeFromBase(ProtocolDataBase protocolDataBase) {
        Cmd106 cmd = new Cmd106();
        cmd.copyDataFrom(protocolDataBase);
        byte[] dataField = protocolDataBase.getDataField();
        //数据域长度
        int len = dataField.length;
        if (len < 101) {
            cmd.setResult(DecodeEnum.InvalidData);
            return cmd;
        }
        int offset = 0;
        cmd.v1 = getUint16(dataField, offset);
        offset += 2;
        cmd.v2 = getUint16(dataField, offset);
        offset += 2;
        // 32字节充电桩编码
        cmd.sn = byteToAscii(Arrays.copyOfRange(dataField, offset, offset + 32), true);
        offset += 32;
        // 1字节标志
        // bit0: 0-不支持加密 1-支持加密
        cmd.sign = getBits(dataField[offset++], 0, 1);
        // 4字节充电桩软件版本
        int intVer = getInt32(dataField, offset);
        cmd.softwareVer = new BigDecimal(intVer).divide(new BigDecimal(100), 2, BigDecimal.ROUND_DOWN).toString();
        offset += 4;
        // 2字节充电桩项目类型， 预留
        offset += 2;
        // 4字节启动次数
        cmd.startNum = getInt32(dataField, offset);
        offset += 4;
        // 1字节数据上传模式
        cmd.uploadMode = getUint8(dataField[offset++]);
        // 2字节签到间隔时间
        cmd.signInterval = getUint16(dataField, offset);
        offset += 2;
        // 1字节运行内部变量
        cmd.innerVariate = getUint8(dataField[offset++]);
        // 1字节充电枪个数
        cmd.pileNum = getUint8(dataField[offset++]);
        // 1字节心跳上报周期
        cmd.heartbeatPeriod = getUint8(dataField[offset++]);
        // 1字节心跳包检测超时次数
        cmd.overtimeCount = getUint8(dataField[offset++]);
        // 4字节充电记录数量
        cmd.chargingRecordCount = getInt32(dataField, offset);
        offset += 4;
        // 8字节当前充电桩系统时间
        cmd.currentTime = getStandardTime(dataField, offset);
        offset += 8;
        // 8字节预留
        cmd.v3 = byteToAscii(Arrays.copyOfRange(dataField, offset, offset + 8), true);
        offset += 8;
        // 8字节预留
        cmd.v4 = byteToAscii(Arrays.copyOfRange(dataField, offset, offset + 8), true);
        offset += 8;
        // 8字节预留
        cmd.v5 = byteToAscii(Arrays.copyOfRange(dataField, offset, offset + 8), true);
        offset += 8;
        // 4字节桩生成随机数
        cmd.randomNumber = getInt32(dataField, offset);
        offset += 4;
        // 2字节桩后台通信协议版本
        int intProtocolVer = getUint16(dataField, offset);
        cmd.protocolVer = new BigDecimal(intProtocolVer).divide(BigDecimal.TEN, 2, BigDecimal.ROUND_DOWN).toString();
        offset += 2;
        // 4字节白名单版本号
        cmd.whitelistVer = getInt32(dataField, offset);
        offset += 4;
        // 1字节设备类型
        cmd.deviceType = getUint8(dataField[offset++]);
        return cmd;
    }

    /**
     * 测试 106签到时使用该方法
     * @return
     */
    @Override
    public byte[] getDataField() {
        int offset = 0;
        byte[] data = new byte[MIN_SIZE];
        getBytesAsUint16(data, offset, this.v1);
        offset += 2;
        getBytesAsUint16(data, offset, this.v2);
        offset += 2;
        // 32字节用户卡号/用户识别号
        encodeAscii(data, sn, 32, offset);
        offset += 32;
        // 1字节 加密标志
        data[offset++] = (byte) this.sign;
        // 4字节 软件版本
        int v = BigDecimal.valueOf(Double.parseDouble(this.softwareVer)).multiply(BigDecimal.valueOf(100)).intValue();
        intToBytesLittle(data, offset, v);
        offset += 4;
        // 充电桩项目类型
        getBytesAsUint16(data, offset, this.projectType);
        offset += 2;
        //启动次数
        intToBytesLittle(data, offset, this.startNum);
        offset += 4;
        // 上传模式
        data[offset++] = (byte) this.uploadMode;
        //签到间隔时间
        getBytesAsUint16(data, offset, this.signInterval);
        offset += 2;

        // 1字节运行内部变量
        data[offset++] = (byte) this.innerVariate;

        // 1字节 充电桩个数
        data[offset++] = (byte) this.pileNum;

        // 1字节 心跳上报周期
        data[offset++] = (byte) this.heartbeatPeriod;

        // 1字节 心跳包检测超时次数
        data[offset++] = (byte) this.overtimeCount;

        // 4字节 充电记录数量
        intToBytesLittle(data, offset, this.chargingRecordCount);
        offset += 4;

        // 8字节平台标准 BCD 时间
        encodeBasicTime(currentTime, data, offset, true);
        offset += 8;
        // 预留8字节
        for(int i=0; i<8; i++){
            data[offset + i] = 0;
        }
        // 预留8字节
        for(int i=0; i<8; i++){
            data[offset + i] = 0;
        }
        // 预留8字节
        for(int i=0; i<8; i++){
            data[offset + i] = 0;
        }

        // 桩生成随机数
        intToBytesLittle(data, offset, this.randomNumber);
        offset += 4;

        // 桩后台通信协议版本
        int pv = new BigDecimal(this.protocolVer).multiply(BigDecimal.TEN).intValue();
        getBytesAsUint16(data, offset, pv);
        offset += 4;

        // 4字节 白名单版本号
        intToBytesLittle(data, offset, this.whitelistVer);
        offset += 4;

        // 1字节 设备类型
        data[offset++] = (byte) this.deviceType;

        return data;
    }

    @Override
    public String toString() {

        StringBuffer buffer = new StringBuffer();
        buffer.append("#cmd106#").append("\n");
        buffer.append("v1:").append(v1).append("\n");
        buffer.append("v2:").append(v2).append("\n");
        buffer.append("充电桩编码:").append(sn).append("\n");
        buffer.append("标志:").append(sign).append("\n");
        buffer.append("充电桩软件版本:").append(softwareVer).append("\n");             //
        buffer.append("充电桩项目类型:").append(projectType).append("\n");                //
        buffer.append("启动次数:").append(startNum).append("\n");                   //
        buffer.append("数据上传模式: 1：应答模式 2：主动上报模式:").append(uploadMode).append("\n");                 //
        buffer.append("签到间隔时间:").append(signInterval).append("\n");               //
        buffer.append("运行内部变量: 0:正常工作模式 1:IAP 模式:").append(innerVariate).append("\n");               //
        buffer.append("充电枪个数:").append(pileNum).append("\n");                    //
        buffer.append("心跳上报周期:").append(heartbeatPeriod).append("\n");            //
        buffer.append("心跳包检测超时次数:").append(overtimeCount).append("\n");              //
        buffer.append("充电记录数量:").append(chargingRecordCount).append("\n");        //
        buffer.append("当前充电桩系统时间:").append(currentTime).append("\n");             //
        buffer.append("预留字段v3:").append(v3).append("\n");
        buffer.append("预留字段v4:").append(v4).append("\n");
        buffer.append("预留字段v5:").append(v5).append("\n");
        buffer.append("桩生成随机数:").append(randomNumber).append("\n");               //
        buffer.append("桩后台通信协议版本:").append(protocolVer).append("\n");       //
        buffer.append("白名单版本号:").append(whitelistVer).append("\n");               //
        buffer.append("设备类型: 0 充电桩 1 集中器:").append(deviceType).append("\n");                 //
        return buffer.toString();
    }
}
